﻿using System;
using susi.util.math;
using UnityEngine;

namespace com.susi.util {
    /// <summary>
    /// 解决RectTransform视图代码不一致的问题
    /// </summary>
    public static class RectTransformExtensions {
        private const float PrecisionTolerance = 0.005f;

        /// <summary>
        /// 对应UGUI上RectTransform的锚点类型
        /// </summary>
        [Flags]
        public enum AnchorsType {
            Custom,
            Top,
            Middle,
            Bottom,
            VerticalStretch, //纵向拉伸
            Left,
            Center,
            Right,
            HorizontalStretch //水平拉伸
        }

        /// <summary>
        /// 仅当Rect锚点为水平拉伸有效
        /// </summary>
        public static float GetLeft(this RectTransform transform)
        {
            Debug.Assert(transform.GetAnchorsType().HasFlag(AnchorsType.HorizontalStretch), $"it is not match the stretch anchor type.it may not right.");
            return transform.offsetMin.x;
        }

        /// <summary>
        /// 仅当Rect锚点为水平拉伸有效
        /// </summary>
        public static float GetRight(this RectTransform transform)
        {
            Debug.Assert(transform.GetAnchorsType().HasFlag(AnchorsType.HorizontalStretch), $"it is not match the stretch anchor type.it may not right.");
            return transform.offsetMax.x;
        }

        /// <summary>
        /// 仅当Rect锚点为纵向拉伸有效
        /// </summary>
        public static float GetTop(this RectTransform transform)
        {
            Debug.Assert(transform.GetAnchorsType().HasFlag(AnchorsType.VerticalStretch), $"it is not match the stretch anchor type.it may not right.");
            return transform.offsetMax.y;
        }

        /// <summary>
        /// 仅当Rect锚点为纵向拉伸有效
        /// </summary>
        public static float GetBottom(this RectTransform transform)
        {
            Debug.Assert(transform.GetAnchorsType().HasFlag(AnchorsType.VerticalStretch), $"it is not match the stretch anchor type.it may not right.");
            return transform.offsetMin.y;
        }

        /// <summary>
        /// 仅当Rect锚点为全屏锚有效
        /// </summary>
        public static Vector2 GetLeftBottom(this RectTransform transform)
        {
            Debug.Assert(transform.GetAnchorsType() == (AnchorsType.VerticalStretch | AnchorsType.HorizontalStretch), $"it is not match the stretch anchor type.it may not right.");
            return transform.offsetMin;
        }

        /// <summary>
        /// 仅当Rect锚点为全屏锚有效
        /// </summary>
        public static Vector2 GetRightTop(this RectTransform transform)
        {
            Debug.Assert(transform.GetAnchorsType() == (AnchorsType.VerticalStretch | AnchorsType.HorizontalStretch), $"it is not match the stretch anchor type.it may not right.");
            return transform.offsetMax;
        }

        /// <summary>
        /// 仅当Rect锚点为全屏锚有效
        /// </summary>
        public static void SetRightTop(this RectTransform transform, Vector2 right_top)
        {
            Debug.Assert(transform.GetAnchorsType() == (AnchorsType.VerticalStretch | AnchorsType.HorizontalStretch), $"it is not match the stretch anchor type.it may not right.");
            transform.offsetMax = right_top;
        }

        /// <summary>
        /// 仅当Rect锚点为全屏锚有效
        /// </summary>
        public static void SetLeftBottom(this RectTransform transform, Vector2 left_bottom)
        {
            Debug.Assert(transform.GetAnchorsType() == (AnchorsType.VerticalStretch | AnchorsType.HorizontalStretch), $"it is not match the stretch anchor type.it may not right.");
            transform.offsetMin = left_bottom;
        }

        public static float GetWidth(this RectTransform transform)
        {
            return transform.rect.width;
        }

        public static float GetHeight(this RectTransform transform)
        {
            return transform.rect.height;
        }

        public static AnchorsType GetAnchorsType(this RectTransform transform)
        {
            var anchorMin = transform.anchorMin;
            var anchorMax = transform.anchorMax;

            AnchorsType horizontal;
            if (Math.Abs(anchorMin.x - anchorMax.x) < PrecisionTolerance) {
                switch (anchorMin.x) {
                    case 0f:
                        horizontal = AnchorsType.Left;
                        break;
                    case 0.5f:
                        horizontal = AnchorsType.Center;
                        break;
                    case 1f:
                        horizontal = AnchorsType.Right;
                        break;
                    default:
                        horizontal = AnchorsType.Custom;
                        break;
                }
            }
            else if (anchorMin.x == 0f && Math.Abs(anchorMax.x - 1f) < PrecisionTolerance) {
                horizontal = AnchorsType.HorizontalStretch;
            }
            else {
                horizontal = AnchorsType.Custom;
            }

            if (horizontal == AnchorsType.Custom) return AnchorsType.Custom;

            AnchorsType vertical;
            if (Math.Abs(anchorMin.y - anchorMax.y) < PrecisionTolerance) {
                switch (anchorMin.y) {
                    case 0f:
                        vertical = AnchorsType.Bottom;
                        break;
                    case 0.5f:
                        vertical = AnchorsType.Middle;
                        break;
                    case 1f:
                        vertical = AnchorsType.Top;
                        break;
                    default:
                        vertical = AnchorsType.Custom;
                        break;
                }
            }
            else if (anchorMin.y == 0 && Math.Abs(anchorMax.y - 1f) < PrecisionTolerance) {
                vertical = AnchorsType.VerticalStretch;
            }
            else {
                vertical = AnchorsType.Custom;
            }

            if (vertical == AnchorsType.Custom) return AnchorsType.Custom;
            return horizontal | vertical;
        }

        /// <summary>
        /// 不能预料会发生的问题，包括但不限于移位；只支持单个锚点类型
        /// </summary>
        public static void SetAnchorsType(this RectTransform transform, AnchorsType anchorsType)
        {
            switch (anchorsType) {
                case AnchorsType.Top:
                    transform.anchorMin = new Vector2(transform.anchorMin.x, 1f);
                    transform.anchorMax = new Vector2(transform.anchorMax.x, 1f);
                    break;
                case AnchorsType.Middle:
                    transform.anchorMin = new Vector2(transform.anchorMin.x, 0.5f);
                    transform.anchorMax = new Vector2(transform.anchorMax.x, 0.5f);
                    break;
                case AnchorsType.Bottom:
                    transform.anchorMin = new Vector2(transform.anchorMin.x, 0f);
                    transform.anchorMax = new Vector2(transform.anchorMax.x, 0f);
                    break;
                case AnchorsType.VerticalStretch:
                    transform.anchorMin = new Vector2(transform.anchorMin.x, 0f);
                    transform.anchorMax = new Vector2(transform.anchorMax.x, 1f);
                    break;
                case AnchorsType.Left:
                    transform.anchorMin = new Vector2(0f, transform.anchorMin.y);
                    transform.anchorMax = new Vector2(0f, transform.anchorMax.y);
                    break;
                case AnchorsType.Center:
                    transform.anchorMin = new Vector2(0.5f, transform.anchorMin.y);
                    transform.anchorMax = new Vector2(0.5f, transform.anchorMax.y);
                    break;
                case AnchorsType.Right:
                    transform.anchorMin = new Vector2(1f, transform.anchorMin.y);
                    transform.anchorMax = new Vector2(1f, transform.anchorMax.y);
                    break;
                case AnchorsType.HorizontalStretch:
                    transform.anchorMin = new Vector2(0f, transform.anchorMin.y);
                    transform.anchorMax = new Vector2(1f, transform.anchorMax.y);
                    break;
                case AnchorsType.Custom:
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(anchorsType), anchorsType, null);
            }
        }

        public static void SetHorizontalMiddle(this RectTransform transform)
        {
            transform.anchoredPosition = new Vector2(0, transform.anchoredPosition.y);
        }

        public static void SetVerticalMiddle(this RectTransform transform)
        {
            transform.anchoredPosition = new Vector2(transform.anchoredPosition.x, 0);
        }

        public static void SetHorizontalAndVerticalMiddle(this RectTransform transform)
        {
            transform.anchoredPosition = new Vector2(0, 0);
        }

        /// <summary>
        /// 基于范围结点宽度，设置其百分比（小数表示）水平位置。当0时，本结点右侧完全超出指定结点左侧，当1时本结点左侧完全超出指定结点右侧。仅针对中心点在中心的本结点设计。范围结点应为全屏锚
        /// </summary>
        public static void SetHorizontalPercentOfRange(this RectTransform transform, RectTransform rangeRect, float prececnt)
        {
            Debug.Assert(rangeRect.GetAnchorsType() == (AnchorsType.HorizontalStretch | AnchorsType.VerticalStretch), "rangRect is invalid about anchorsType.");
            Debug.Assert(Math.Abs(transform.pivot.x - 0.5f) < PrecisionTolerance, "self is not pivot in center.");
            var rangewidth = rangeRect.GetWidth();
            var selfwidth  = transform.GetWidth();
            var xmin       = -selfwidth * 0.5f;
            var xmax       = rangewidth + selfwidth * 0.5f;
            var position   = transform.position;
            position.x         = MathLibrary.Remap(prececnt, 0f, 1f, xmin, xmax);
            transform.position = position;
        }
    }
}